﻿namespace TestTool.HttpTransport
{
    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.ServiceModel;
    using System.Threading;

    internal class RequestNetworkStream
    {
        private bool _active;
        private EndPoint _endpoint;
        private NetworkStream _networkStream;
        private Socket _socket;
        private EndpointAddress _to;

        public RequestNetworkStream(EndpointAddress to)
        {
            this._to = to;
        }

        public IAsyncResult BeginRead(byte[] buffer, int offset, int size)
        {
            return this._networkStream.BeginRead(buffer, offset, size, null, null);
        }

        public void Close()
        {
            if (this._networkStream != null)
            {
                this._networkStream.Close();
            }
            if ((this._socket != null) && this._socket.Connected)
            {
                this._socket.Close();
            }
            this._active = false;
        }

        public void Connect()
        {
            IPAddress[] hostAddresses = null;
            IPAddress address;
            if (IPAddress.TryParse(this._to.Uri.Host, out address))
            {
                hostAddresses = new IPAddress[] { address };
            }
            else
            {
                hostAddresses = Dns.GetHostAddresses(this._to.Uri.Host);
            }
            Exception exception = null;
            Socket socket = null;
            Socket socket2 = null;
            try
            {
                if (this._socket == null)
                {
                    if (Socket.SupportsIPv4)
                    {
                        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    }
                    if (Socket.OSSupportsIPv6)
                    {
                        socket2 = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
                    }
                }
                foreach (IPAddress address2 in hostAddresses)
                {
                    try
                    {
                        EndPoint remoteEP = new IPEndPoint(address2, this._to.Uri.Port);
                        if (this._socket == null)
                        {
                            if ((address2.AddressFamily == AddressFamily.InterNetwork) && (socket != null))
                            {
                                socket.Connect(remoteEP);
                                this._endpoint = remoteEP;
                                this._socket = socket;
                                if (socket2 != null)
                                {
                                    socket2.Close();
                                }
                            }
                            else if (socket2 != null)
                            {
                                socket2.Connect(remoteEP);
                                this._endpoint = remoteEP;
                                this._socket = socket2;
                                if (socket != null)
                                {
                                    socket.Close();
                                }
                            }
                            this._active = true;
                            this._networkStream = new NetworkStream(this._socket);
                            return;
                        }
                        if (address2.AddressFamily == AddressFamily.InterNetwork)
                        {
                            this._socket.Connect(remoteEP);
                            this._endpoint = remoteEP;
                            this._active = true;
                            this._networkStream = new NetworkStream(this._socket);
                            return;
                        }
                    }
                    catch (Exception exception2)
                    {
                        if (((exception2 is ThreadAbortException) || (exception2 is StackOverflowException)) || (exception2 is OutOfMemoryException))
                        {
                            throw;
                        }
                        exception = exception2;
                    }
                }
            }
            catch (Exception exception3)
            {
                if (((exception3 is ThreadAbortException) || (exception3 is StackOverflowException)) || (exception3 is OutOfMemoryException))
                {
                    throw;
                }
                exception = exception3;
            }
            finally
            {
                if (!this._active)
                {
                    if (socket != null)
                    {
                        socket.Close();
                    }
                    if (socket2 != null)
                    {
                        socket2.Close();
                    }
                    if (exception != null)
                    {
                        throw exception;
                    }
                    throw new SocketException(0x2749);
                }
            }
        }

        public int EndRead(IAsyncResult result)
        {
            return this._networkStream.EndRead(result);
        }

        public void EnsureOpen(EndpointAddress address)
        {
            bool flag = this._to != address;
            this._to = address;
            if (this._socket == null)
            {
                flag = true;
            }
            else if (this._socket.Connected)
            {
                if (this._socket.Poll(500, SelectMode.SelectRead))
                {
                    byte[] buffer = new byte[0x20];
                    flag = this._socket.Receive(buffer) == 0;
                }
            }
            else
            {
                flag = true;
            }
            if (flag)
            {
                this._socket = null;
                this.Connect();
            }
        }

        public void Write(byte[] buffer, int offset, int count)
        {
            this._networkStream.Write(buffer, offset, count);
        }

        internal bool Connected
        {
            get
            {
                if (this._socket == null)
                {
                    return false;
                }
                return this._socket.Connected;
            }
        }

        public bool DataAvailable
        {
            get
            {
                return this._networkStream.DataAvailable;
            }
        }

        public int ReadTimeout
        {
            get
            {
                return this._networkStream.ReadTimeout;
            }
            set
            {
                this._networkStream.ReadTimeout = value;
            }
        }
    }
}

